﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Windows.Input;
using BaMusaSoft.RPS.DataModel;
using BaMusaSoft.RPS.DataModel.Repositories;
using BaMusaSoft.RPS.ViewModel.HelperClasses;
using BaMusaSoft.RPS.ViewModel.Infrastructure;
using BaMusaSoft.RPS.ViewModel.Properties;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;

namespace BaMusaSoft.RPS.ViewModel
{
    public class AddScheduleDetailViewModel : Workspace, IDataErrorInfo
    {
        #region "Fields"

        private RelayCommand _addCommand;
        private ScheduleDetail _detail;
        private RepositoryBase<ScheduleDetail> _repository;
        private IUnitOfWork _unitOfWork;
        public event EventHandler<EntityAddedEventArgs<ScheduleDetail>> DetailAdded;

        #endregion

        #region Constructor

        public AddScheduleDetailViewModel(IUnitOfWork unitOfWork)
        {
            if (unitOfWork == null) throw new ArgumentNullException("unitOfWork");
            _unitOfWork = unitOfWork;
            _detail = new ScheduleDetail();
            _repository = unitOfWork.ScheduleDetails;
        }

        #endregion

        #region Binding Properties

        [Bindable(true)]
        public int AmountDue
        {
            get { return _detail.AmountDue; }
            set
            {
                _detail.AmountDue = value;
                RaisePropertyChanged("AmountDue");
            }
        }

        [Bindable(true)]
        public string DateDue
        {
            get { return _detail.DateDue; }
            set
            {
                _detail.DateDue = value;
                RaisePropertyChanged("DateDue");
            }
        }

        [Bindable(true)]
        public string Remarks
        {
            get { return _detail.Remarks; }
            set
            {
                _detail.Remarks = value;
                RaisePropertyChanged("Remarks");
            }
        }

        #endregion

        #region Overrides of Workspace

        public override string DisplayName
        {
            get { throw new NotImplementedException(); }
            protected set { throw new NotImplementedException(); }
        }

        public override bool HasChanges
        {
            get { throw new NotImplementedException(); }
        }

        #endregion

        #region "Commands"

        public ICommand AddCommand
        {
            get { return _addCommand ?? (_addCommand = new RelayCommand(AddDetail)); }
        }

        private void AddDetail()
        {
            if (!ValidModel()) return;

            OnDetailAdded(_detail);
            _detail = new ScheduleDetail();
            RefreshBinding();
            OnStateChanged(ViewModelState.New);
        }

        #endregion

        #region "Helpers"

        private void OnDetailAdded(ScheduleDetail entity)
        {
            if (DetailAdded != null)
            {
                DetailAdded(this, new EntityAddedEventArgs<ScheduleDetail>(entity));
            }
        }

        private void RefreshBinding()
        {
            IEnumerable<PropertyInfo> bindableProperties = from p in typeof (AddScheduleDetailViewModel).GetProperties()
                                                           where
                                                               p.GetCustomAttributes(true).Cast<Attribute>().Contains(
                                                                   new BindableAttribute(true))
                                                           select p;

            foreach (PropertyInfo p in bindableProperties)
            {
                RaisePropertyChanged(p.Name);
            }
        }

        private void OnStateChanged(ViewModelState state)
        {
            switch (state)
            {
                case ViewModelState.New:
                    Messenger.Default.Send(state, this);
                    break;
                case ViewModelState.Saved:
                    break;
                case ViewModelState.Deleted:
                    break;
                default:
                    throw new ArgumentOutOfRangeException("state");
            }
        }

        private bool ValidModel()
        {
            ClearAllErrors();
            bool valid = true;
            if (AmountDue <= 0)
            {
                string msg = Resources.AmountDueErrMsg;
                SetError("AmountDue", msg);
                valid = false;
            }
            if (string.IsNullOrEmpty(DateDue) || !Helper.IsValidDate(DateDue))
            {
                string msg = Resources.DateDueErrMsg;
                SetError("DateDue", msg);
                valid = false;
            }


            return valid;
        }

        #endregion

        #region Implementation of IDataErrorInfo

        private readonly Dictionary<string, string> _errors = new Dictionary<string, string>();

        /// <summary>
        /// Gets the error message for the property with the given name.
        /// </summary>
        /// <returns>
        /// The error message for the property. The default is an empty string ("").
        /// </returns>
        /// <param name="columnName">The name of the property whose error message to get. </param>
        public string this[string columnName]
        {
            get { return _errors.ContainsKey(columnName) ? _errors[columnName] : string.Empty; }
        }

        /// <summary>
        /// Gets an error message indicating what is wrong with this object.
        /// </summary>
        /// <returns>
        /// An error message indicating what is wrong with this object. The default is an empty string ("").
        /// </returns>
        public string Error
        {
            get { return null; }
        }

        private void SetError(string propertyName, string errorMessage)
        {
            _errors[propertyName] = errorMessage;
            RaisePropertyChanged(propertyName);
        }

        private void ClearAllErrors()
        {
            List<string> proeprties = _errors.Select(error => error.Key).ToList();
            _errors.Clear();
            foreach (string property in proeprties)
            {
                RaisePropertyChanged(property);
            }
        }

        #endregion
    }
}